﻿using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Ymatou.PerfMonitorClient;
using YmtAuth.Common.Extend;
using YmtAuth.Domain.DomainEvent;
using YmtAuth.Domain.EventHistory;
using YmtAuth.Domain.Model.BlacklistUser;
using YmtAuth.Domain.Model.Safe;
using YmtAuth.Domain.Repository;
using YmtAuth.Domain.Shard;
using YmtSystem.CrossCutting;
using YmtSystem.Infrastructure.EventBusService;

namespace YmtAuth.Domain.Model.Safe
{
   [Obsolete("wesley-区分买手、买家的app和pc风控策略")]
    public class PcSafeVerify
    {
        /// <summary>
        /// 总开关检查
        /// </summary>
        public class PcSafeCfgSwitchVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerPc-PcSafeCfgSwitchVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_Pc_Open, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-PC开关, 【LoginSafe_Pc_Open】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin);
                }
                return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
            }
        }

        /// <summary>
        /// PC端 登录历史密码验证
        /// </summary>
        public class LoginPasswordHistoryVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerPc-LoginPasswordHistoryVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                //验证是否开启登录密码错误历史检查
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcLoginPas_Check, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-校验登录历史错误密码, 【LoginSafe_PcLoginPas_Check】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                var pasCfg = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcLoginPas_CheckSpec, "-10,6");
                var splitCfg = pasCfg.Split(new char[] {','});
                if (splitCfg == null || splitCfg.Length != 2)
                {
                    splitCfg = new string[] {"-10", "6"};
                    YmatouLoggingService.Debug("PC登录历史错误密码检查配置错误使用默认配置");
                }
                var loginFailTimeMinutes = splitCfg[0].ConvertToInt32(-10);
                var loginFailCount = splitCfg[1].ConvertToInt32(6);

                return CommonStrategy.loginPasswordHistoryVerify(par, repo, cfg, loginFailTimeMinutes, loginFailCount);
            }
        }

        /// <summary>
        /// PC端 登录IP验证策略
        /// </summary>
        public class IpAreaVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerPc-IpAreaVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                AuthSafeHandleCode authSafeHandleCode = null;
                
                //检查是否开启IP区域存在性验证
                if (cfg.SafeCfg.TryGet(SafeCfgKey.KeyFormart(SafeCfgKey.LoginSafe_PcIp_ExistsCheck,par.Source), "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-IP区域检查, 【LoginSafe_PcIp_ExistsCheck】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                if (string.IsNullOrEmpty(par.Ip))
                {
                    var _code =
                        cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcIp_NotExistsIdentityVerify, "100")
                            .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                    string msg = string.Format("用户{0}，IP为空，执行{1}", par.LoginId, _code);

                    if (AuthSafeHandleCode.NeedIdentityVerify == _code)
                    {
                        authSafeHandleCode = AuthSafeHandleCode.CreateCode(_code, AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_IPNotExists, msg);
                    }
                    else 
                        authSafeHandleCode = AuthSafeHandleCode.CreateCode(_code, msg);

                    YmatouLoggingService.Debug("登录风控-IP区域检查, {0}, requestId: {1}", msg, par.RequestId);
                    return authSafeHandleCode;
                }               
                //获取IP区域原始数据,不存在则不需要身份验证
                var watch = Stopwatch.StartNew();
                var ipAreaRawInfo = repo.IpAreaRepo.FindIpAreaInfo(IpAreaInfoAuthEntity.IpConvertToLong(par.Ip));
                watch.Stop();
                if (ipAreaRawInfo == null)
                {
                    //TODO 发布原始IP区域数据不存在事件
                    EventBus.Instance.Publish(new LoginSafeVerifyEvent
                    {
                        UserId = par.UserId,
                        AppSource = par.Source,
                        AuthType = "IpAreaVerify",
                        ResponseCode = AuthSafeHandleCode.RawIpNotFind,
                        LoginId = par.LoginId,
                        LoginIp = par.Ip,
                        Desc = "IP库原始数据不存在,执行下个安全认证",
                        RunTime = watch.Elapsed.TotalMilliseconds
                    });
                    using (var mm = MethodMonitor.New("IpAreaRaw_NotFind"))
                    {
                    }
                    YmatouLoggingService.Debug("登录风控-IP区域检查, IP库原始数据不存在,执行下个安全认证, LoginId: {0}, ip: {1}, requestId: {2}", par.LoginId, par.Ip, par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //开启用户第一次登录，自动初始化该IP为常用登录Ip
                var autoAuth = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcUserFirstLogin_AutoAuthSuccess, "0");
                if (autoAuth == "1" && UserIpAreaFirstAutoAuth(par, ipAreaRawInfo, repo.IpAreaRepo))
                {
                    YmatouLoggingService.Debug("登录风控-IP区域检查, 开启用户第一次登录，自动初始化该IP为常用登录, requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //获取IP区域认证数据,不存在则需要身份验证 
                watch.Restart();
                IpAreaInfoAuthEntity ipAreaInfo = null;
                //如果是来源是买手则忽略市
                if (YmatouBlacklistUserSpecifications.IsSellerSource(par.Source))
                {
                    //如果是国外IP则只匹配国家，国内Ip匹配国家&省份
                    if (ipAreaRawInfo.Country.ToLower() != "china" && ipAreaRawInfo.Country.ToLower() != "lan")
                    {
                        ipAreaInfo = repo.IpAreaRepo.FindAreaInfoAuthEntity(par.UserId, ipAreaRawInfo.Country,ipAreaRawInfo.Province,200);  
                    }
                    else
                    {
                        ipAreaInfo = repo.IpAreaRepo.FindAreaInfoAuthEntity(par.UserId, ipAreaRawInfo.Country,
                        ipAreaRawInfo.Province, ipAreaRawInfo.City/*, 200*/);  
                    }                  
                }
                else
                {
                    ipAreaInfo = repo.IpAreaRepo.FindAreaInfoAuthEntity(par.UserId, ipAreaRawInfo.Country,
                      ipAreaRawInfo.Province, ipAreaRawInfo.City);
                }  
                watch.Stop();
                var code = AuthSafeHandleCode.ContinueNextVerify;
                var desc = "";
                if (ipAreaInfo == null)
                {
                    code =
                        cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcIp_NotExistsIdentityVerify, "100")
                            .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                    desc = string.Format("IP区域不存在,执行Code_{0}", code);

                    YmatouLoggingService.Debug("登录风控-IP区域检查, {0}, requestId: {1}", desc, par.RequestId);

                    if (AuthSafeHandleCode.NeedIdentityVerify == code)
                    {
                        authSafeHandleCode = AuthSafeHandleCode.CreateCode(code
                            , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_CannotFindIpArea
                            , desc
                            , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                    }
                    else
                        authSafeHandleCode = AuthSafeHandleCode.CreateCode(code, desc);
                    
                    EventBus.Instance.Publish(new LoginSafeVerifyEvent
                    {
                        UserId = par.UserId,
                        AppSource = par.Source,
                        AuthType = "IpAreaVerify",
                        ResponseCode = authSafeHandleCode.SubCode,
                        IpArea = ipAreaRawInfo.GetArea(),
                        LoginId = par.LoginId,
                        LoginIp = par.Ip,
                        Desc = string.Format("{0}", desc),
                        RunTime = watch.Elapsed.TotalMilliseconds
                    });
                }
                else
                {
                    //存在IP区域认证数据则再次执行认证，

                    authSafeHandleCode = new IpBlackListVerify().Execute(par, repo, cfg);
                    if (authSafeHandleCode.Code == AuthSafeHandleCode.NeedIdentityVerify ||
                        authSafeHandleCode.Code == AuthSafeHandleCode.DenyLogin)
                    {
                        YmatouLoggingService.Debug("登录风控-IP区域检查, {0}, requestId: {1}", authSafeHandleCode.Message, par.RequestId);
                        return authSafeHandleCode;
                    }

                    authSafeHandleCode = VerifyIPAreaStatus(par, cfg, ipAreaInfo);
                }

                return authSafeHandleCode;
            }

            private bool UserIpAreaFirstAutoAuth(UserLoginParameter par, IpAreaInfoAuthEntity.IpAreaInfo rawAreaInfo,
                IIpAreaInfoRepository repo)
            {
                var watch = Stopwatch.StartNew();
                var firstAuthInfo = repo.FindUserFirstAuthAreaInfo(par.UserId, 200).FirstOrDefault();
                watch.Stop();
                //如果用户IP区域大于2条数据且存在非当前登录区域认证记录，则表示不是第一次登录
                if (firstAuthInfo != null)
                {
                    if (firstAuthInfo.UserId == par.UserId && firstAuthInfo.Country == rawAreaInfo.Country &&
                        firstAuthInfo.Province == rawAreaInfo.Province && firstAuthInfo.City == rawAreaInfo.City
                        && firstAuthInfo.AuthStatus == -200)
                    {
                        YmatouLoggingService.Debug("用户第一次登录IP区域已认证失败 {0},{1}", par.UserId, par.Ip);
                        return false;
                    }
                    if ((firstAuthInfo.Country != rawAreaInfo.Country ||
                         firstAuthInfo.Province != rawAreaInfo.Province
                         || firstAuthInfo.City != rawAreaInfo.City)
                        && firstAuthInfo.AuthStatus == 200)
                    {
                        YmatouLoggingService.Debug("用户非第一次登录IP区域已认证{0},{1}", par.UserId, par.Ip);
                        return false;
                    }
                }
                else
                    firstAuthInfo = new IpAreaInfoAuthEntity(par.UserId, rawAreaInfo.Country, rawAreaInfo.Province,
                        rawAreaInfo.City,par.Ip, par.Source);
                firstAuthInfo.SetAuthStatus(true, IPAreaSourceType.Login);
                repo.TrySaveChange(firstAuthInfo,
                    ex =>
                        YmatouLoggingService.Error(
                            "TrySaveChange firstIPAreaAuthInfo userID:{0},Country:{1},Province:{2},City:{3},ex:{4}",
                            par.UserId,
                            rawAreaInfo.Country, rawAreaInfo.Province, rawAreaInfo.City, ex.ToString()));
                var desc = "用户IP区域第一次认证，自动认证成功";
                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "VerifyLoginIpArea",
                    ResponseCode = AuthSafeHandleCode.UserIpAreaFirstAutoAuth,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = string.Format("{0}", desc),
                    RunTime = watch.Elapsed.TotalMilliseconds
                });
                YmatouLoggingService.Debug("source {0},loginid {1},{2}", par.Source, par.LoginId, desc);
                return true;
            }

            //IP区域状态验证
            private AuthSafeHandleCode VerifyIPAreaStatus(UserLoginParameter par, AuthSafeConfiguration cfg,
                IpAreaInfoAuthEntity ipAreaInfo)
            {
                //检查是否开启IP区域认证状态检查
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcIp_AuthStatusCheck, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-IP区域状态验证, 【LoginSafe_PcIp_AuthStatusCheck】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //IP 区域未认证，认证失败需要用户身份验证
                var watch = Stopwatch.StartNew();
                var code = 0;
                var desc = "";
                if (!ipAreaInfo.AuthIsSuccess())
                {
                    code =
                        cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcIp_AuthFailAction, "100")
                            .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                    desc = string.Format("IP区域认证未认证或者认证失败，执行Code_{0}",code);                      
                }
                else
                {                   
                    code =
                        cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcIp_AuthSuccessAction, "200")
                            .ConvertToInt32(AuthSafeHandleCode.ContinueNextVerify);
                    desc = string.Format("IP区域认证成功，执行Code_{0}",code);                      
                }
                watch.Stop();
                
                AuthSafeHandleCode res = null;

                if (AuthSafeHandleCode.NeedIdentityVerify == code)
                {
                    res = AuthSafeHandleCode.CreateCode(code
                        , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_VerifyIPAreaStatus
                        , desc
                        , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                }
                else
                {
                    res = AuthSafeHandleCode.CreateCode(code, desc);
                }

                //TODO 发布IP区域认证未认证或不通过事件
                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "VerifyIPAreaStatus",
                    ResponseCode = res.SubCode,
                    IpArea = ipAreaInfo.GetArea(),
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = string.Format("{0}", desc),
                    RunTime = watch.Elapsed.TotalMilliseconds
                });

                YmatouLoggingService.Debug("登录风控-IP区域状态验证, {0}; LoginId: {1}, Ip: {2}, AuthStatus: {3}, requestId: {4}", desc, par.LoginId, par.Ip, ipAreaInfo.AuthStatus, par.RequestId);

                return res;
            }
        }

        /// <summary>
        /// PC端 IP 黑名单验证
        /// </summary>
        public class IpBlackListVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerPc-IpBlackListVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.KeyFormart(SafeCfgKey.LoginSafe_PcBlacklist_Check,par.Source), "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-IP黑名单验证, 【LoginSafe_PcBlacklist_Check】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //
                var watch = Stopwatch.StartNew();
                var _ip = repo.IpBlackListRepo.FindOne(YmatouBlacklistUserSpecifications.MathRequestIP(par.Ip)
                    , YmatouBlacklistUserSpecifications.GetBlacklistDbName()
                    , YmatouBlacklistUserSpecifications.GetBlacklistTableName(par.Source));
                watch.Stop();
                var code = AuthSafeHandleCode.ContinueNextVerify;
                var desc = "此Ip不在黑名单,执行下个安全认证";
                //如果是黑名单且禁止登录时间未到期,则（根据配置）执行身份验证或者拒绝登录
                DateTime? expiredTime = null ;
                if (_ip != null)
                {
                    if (_ip.IsDisableRequest())
                    {
                        code =cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcBlacklist_BlacklistAction, "100")
                                .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                        desc = string.Format("此IP为黑名单IP，执行Code_{0}", code);                          
                    }
                    else
                    {
                        code = AuthSafeHandleCode.ContinueNextVerify;
                        desc = "此Ip在黑名单,锁定时间超时,执行下个安全认证";
                    }

                    expiredTime = _ip.ExpiredTime.ToLocalTime();
                }

                AuthSafeHandleCode res = null;
                if (AuthSafeHandleCode.NeedIdentityVerify == code)
                {
                    res = AuthSafeHandleCode.CreateCode(code
                        , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_BlackIPVerify
                        , desc
                        , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                }
                else
                {
                    res = AuthSafeHandleCode.CreateCode(code, desc);
                }

                //TODO 发布用户IP黑名单事件
                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "IpBlackListVerify",
                    ResponseCode = res.SubCode,
                    ExpiredTime = expiredTime,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = string.Format("{0}", desc),
                    RunTime = watch.Elapsed.TotalMilliseconds
                });

                YmatouLoggingService.Debug("登录风控-IP黑名单验证, LoginId: {0}, desc: {1}, requestId: {2}", par.LoginId, desc, par.RequestId);

                return res;
            }
        }

        /// <summary>
        /// 用户最后一次IP区域认证时间验证
        /// 注：最后一个事件返回；要么验证身份，要么直接登录
        /// </summary>
        public class TokenLastTimeVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerPc-TokenLastTimeVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                string desc = string.Empty;

                //用户最后一次IP区域认证检查
                if (cfg.SafeCfg.TryGet(SafeCfgKey.KeyFormart(SafeCfgKey.LoginSafe_PcToken_Check,par.Source), "1") != "1")
                {
                    desc = string.Format("LoginSafe_PcToken_Check is false");
                    YmatouLoggingService.Debug("登录风控-用户最后一次IP区域认证, 【LoginSafe_PcToken_Check】 is false; requestId: {0}", par.RequestId);

                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin, desc);
                }
                var watch = Stopwatch.StartNew();
                var rawIpRearInfo = repo.IpAreaRepo.FindIpAreaInfo(IpAreaInfoAuthEntity.IpConvertToLong(par.Ip));
                watch.Stop();
                if (rawIpRearInfo == null)
                {
                    EventBus.Instance.Publish(new LoginSafeVerifyEvent
                    {
                        UserId = par.UserId,
                        AppSource = par.Source,
                        AuthType = "VerifyIpAreaLastAuthTime",
                        ResponseCode = AuthSafeHandleCode.AllowLogin,
                        LoginId = par.LoginId,
                        LoginIp = par.Ip,
                        Desc = "PC端toke最后认证时间检查，原始库不存在IP区域，允许登录",                       
                        RunTime = watch.Elapsed.TotalMilliseconds
                    });

                    desc = string.Format("原始库不存在IP {0} 区域,允许登录,loginId:{1},source:{2}", par.Ip, par.LoginId,
                        par.Source);
                    YmatouLoggingService.Debug("登录风控-用户最后一次IP区域认证, 原始库不存在; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin, desc);
                }
                watch.Restart();
                var lastAuthIpAreaInfo = repo.IpAreaRepo.FindUserLastTokenAuthIpAreaInfo(par.UserId, rawIpRearInfo.Country,
                    rawIpRearInfo.Province, rawIpRearInfo.City);
                watch.Stop();
                if (lastAuthIpAreaInfo == null)
                {
                    EventBus.Instance.Publish(new LoginSafeVerifyEvent
                    {
                        UserId = par.UserId,
                        AppSource = par.Source,
                        AuthType = "VerifyIpAreaLastAuthTime",
                        ResponseCode = AuthSafeHandleCode.AllowLogin,
                        LoginId = par.LoginId,
                        LoginIp = par.Ip,
                        Desc = "最后一次Ip区域认证不存在,允许登录",                      
                        RunTime = watch.Elapsed.TotalMilliseconds
                    });

                    desc = string.Format("用户{0}最后一次Ip区域认证不存在,允许登录", par.LoginId);
                    YmatouLoggingService.Debug("登录风控-用户最后一次IP区域认证, {0}; requestId: {1}", desc, par.RequestId);

                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin, desc);
                }
                if (lastAuthIpAreaInfo.AuthTime == null)
                {
                    desc = string.Format("用户 {0} 最后一次Ip  {1} 区域认证,认证时间为空,执行身份认证", par.LoginId, par.Ip);
                    YmatouLoggingService.Debug("登录风控-用户最后一次IP区域认证, {0}; requestId: {1}", desc, par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.NeedIdentityVerify, desc);
                }
                var subDay = DateTime.Now.Subtract(lastAuthIpAreaInfo.AuthTime.Value).TotalDays;
                var lastDay = cfg.SafeCfg.TryGet(SafeCfgKey.KeyFormart(SafeCfgKey.LoginSafe_PcToken_LastAuthDay,par.Source), "90").ConvertToInt32(90);
                var code = subDay >= lastDay
                    ? AuthSafeHandleCode.NeedIdentityVerify
                    : AuthSafeHandleCode.AllowLogin;
                desc = subDay >= lastDay
                    ? string.Format("最后一次Ip区域认证时间 {0} 大于等于{1}天，执行身份验证", lastAuthIpAreaInfo.AuthTime.Value, lastDay)
                    : string.Format("最后一次Ip区域认证时间 {0} 小于{1}天，允许登录", lastAuthIpAreaInfo.AuthTime.Value, lastDay);
                
                AuthSafeHandleCode res = null;
                if (AuthSafeHandleCode.NeedIdentityVerify == code)
                {
                    res = AuthSafeHandleCode.CreateCode(code
                        , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_VerifyIpAreaLastAuthTime
                        , desc
                        , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                }
                else
                {
                    res = AuthSafeHandleCode.CreateCode(code, desc);
                }

                //TODO 发布最后一次IP区域认证时间事件
                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "VerifyIpAreaLastAuthTime",
                    ResponseCode = res.SubCode,
                    LastAuthTime = lastAuthIpAreaInfo.AuthTime.Value,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = desc,
                    RunTime = watch.Elapsed.TotalMilliseconds
                });

                YmatouLoggingService.Debug("登录风控-用户最后一次IP区域认证, {0}; requestId: {1}", desc, par.RequestId);

                return res;
            }
        }
    }

    [Obsolete("wesley-区分买手、买家的app和pc风控策略")]
    public class AppSafeVerify
    {
        /// <summary>
        /// 总开关检查
        /// </summary>
        public class AppSafeCfgSwitchVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-AppSafeCfgSwitchVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_App_Open, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-APP开关, 【LoginSafe_App_Open】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin);
                }
                return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
            }
        }

        /// <summary>
        /// 对APP端用户最后一次IP区域认证时间检查
        /// </summary>
        public class AppTokenLastTimeCheck : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-AppTokenLastTimeCheck*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                //检查IP区域token认证时间检查
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppIpUserToken_Check, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-APP端用户最后一次IP区域认证时间检查, 【LoginSafe_AppIpUserToken_Check】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin);
                }
                var lastDay = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppToken_LastAuthDay, "90").ConvertToInt32(90);
                return CommonStrategy.CheckUserIpAreaLastAuthTime(par, repo, cfg, lastDay);
            }
        }

        /// <summary>
        /// 登录历史错误密码检查
        /// </summary>
        public class LoginPasswordHistoryVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-LoginPasswordHistoryVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppLoginPas_Check, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-校验登录历史错误密码, 【LoginSafe_AppLoginPas_Check】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //APP验证登录历史密码策略和PC端一样
                var pasCfg = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppLoginPas_CheckSpec, "-10,6");
                var splitCfg = pasCfg.Split(new char[] {','});
                if (splitCfg == null || splitCfg.Length != 2)
                {
                    splitCfg = new string[] {"-10", "6"};
                    YmatouLoggingService.Debug("APP登录历史错误密码检查配置错误使用默认配置");
                }
                var loginFailTimeMinutes = splitCfg[0].ConvertToInt32(-10);
                var loginFailCount = splitCfg[1].ConvertToInt32(6);
                return CommonStrategy.loginPasswordHistoryVerify(par, repo, cfg, loginFailTimeMinutes, loginFailCount);
            }
        }

        /// <summary>
        /// 设备号验证
        /// </summary>
        public class DeviceVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-DeviceVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                //检查开关
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppDevice_ExistsCheck, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-设备号验证开关, 【LoginSafe_AppDevice_ExistsCheck】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //如果设备号，CLientID都为空记录日志
                if (par.DeviceId.IsEmpty() && par.AppClientId.IsEmpty())
                {
                    var code = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppDevice_NotExists, "400").ConvertToInt32(400);
                    string desc = string.Format("用户常用设备为空，ResponseCode:{0}", code);

                    AuthSafeHandleCode res = null;
                    if (AuthSafeHandleCode.NeedIdentityVerify == code)
                    {
                        res = AuthSafeHandleCode.CreateCode(code
                            , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_DeviceAndCLientIdNotExists
                            , desc
                            , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                    }
                    else
                    {
                        res = AuthSafeHandleCode.CreateCode(code, desc);
                    }

                    EventBus.Instance.Publish(new LoginSafeVerifyEvent
                    {
                        UserId = par.UserId,
                        AppSource = par.Source,
                        AuthType = "DeviceVerify",
                        ResponseCode = res.SubCode,
                        LoginId = par.LoginId,
                        LoginIp = par.Ip,
                        Desc = desc,
                        RunTime = 0
                    });
                }
                //用户第一次登录设备，自动认证为成功
                //开启用户第一次登录，自动初始化该设备号为常用登录设备号
                var autoAuth = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppUserFirstLogin_AutoAuthSuccess, "0");
                if (autoAuth=="1" && UserDeviceFirstAutoAuth(par, repo.DeviceRepo))
                {
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //用户非第一次登录，安全流程检查
                //如果客户端传的参数设备号ID存在，则验证设备号是否存在及验证状态                
                if (!par.DeviceId.IsEmpty())
                {
                    var code = VerifyDevice(par, repo, cfg);

                    YmatouLoggingService.Debug("登录风控-设备号验证, DeviceId verify result: {0}, {1}, requestId: {2}", code.Code, code.Message, par.RequestId);
                    return code;
                }
                if (par.DeviceId.IsEmpty() && !par.AppClientId.IsEmpty())
                {
                    var code = VerifyClientId(par, repo, cfg);

                    YmatouLoggingService.Debug("登录风控-ClientId验证, ClientId verify result: {0}, {1}, requestId: {2}", code.Code, code.Message, par.RequestId);
                    return code;
                }
                return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
            }

            private bool UserDeviceFirstAutoAuth(UserLoginParameter par, IUserDeviceAuthRepository repo)
            {
                //用户第一次登录设备，自动认证为成功
                var deviceid = par.DeviceId.IsEmpty() ? par.AppClientId : par.DeviceId;
                var watch = Stopwatch.StartNew();
                var firstAuthDeviceInfo = repo.FindUserFirstAuthDeviceInfo(par.UserId, 200).FirstOrDefault();
                watch.Stop();
                if (firstAuthDeviceInfo != null)
                {
                    if (firstAuthDeviceInfo.DeviceId != deviceid && firstAuthDeviceInfo.AuthIsSuccess())
                    {
                        YmatouLoggingService.Debug("用户非当前设备号，且已认证成功 {0},{1}", par.LoginId, par.UserId);
                        return false;
                    }
                    if (firstAuthDeviceInfo.AuthStatus == -200)
                    {
                        YmatouLoggingService.Debug("用户第一次登录设备号已认证失败 UserId:{0},deviceid:{1}", par.UserId, deviceid);
                        return false;
                    }
                }
                else
                    firstAuthDeviceInfo = new UserDeviceAuthEntity(par.UserId, deviceid, par.Source);
                firstAuthDeviceInfo.SetDeviceAuthStatus(true);
                repo.TrySaveChange(firstAuthDeviceInfo,
                    ex =>
                        YmatouLoggingService.Error(
                            "TrySaveChange firstAuthDeviceInfo error UserId {0},deviceid {1},ex {2}", par.UserId,
                            deviceid, ex.ToString()));
                var desc = "用户第一次登录设备，自动认证";
                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "DeviceVerify",
                    ResponseCode = AuthSafeHandleCode.UserDeviceFirstAutoAuth,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = string.Format("{0}", desc),
                    DeviceId = par.DeviceId,
                    ClientId = par.AppClientId,
                    RunTime = watch.Elapsed.TotalMilliseconds
                });
                
                YmatouLoggingService.Debug("登录风控-设备号检查, loginId: {0}, {1}, requestId: {2}", par.LoginId, desc, par.RequestId);
                return true;
            }

            //验证设备号
            private AuthSafeHandleCode VerifyDevice(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                var code = 0;
                var desc = "";
                var watch = Stopwatch.StartNew();

                watch.Restart();
                var decvice = repo.DeviceRepo.FindUserDevice(par.UserId, par.DeviceId);
                watch.Stop();
                //如果认证库设备号不存在
                if (decvice == null)
                {
                    code = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppDevice_NotExists, "100").ConvertToInt32(100);
                    desc = string.Format("该设备号不存在，执行Code_{0}", code);

                    AuthSafeHandleCode res = null;
                    if (AuthSafeHandleCode.NeedIdentityVerify == code)
                    {
                        res = AuthSafeHandleCode.CreateCode(code
                            , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_CannotFindDevice
                            , desc
                            , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                    }
                    else
                        res = AuthSafeHandleCode.CreateCode(code, desc);

                    EventBus.Instance.Publish(new LoginSafeVerifyEvent
                    {
                        UserId = par.UserId,
                        AppSource = par.Source,
                        AuthType = "UserDeviceExistsCheck",
                        ResponseCode = res.SubCode,
                        LoginId = par.LoginId,
                        LoginIp = par.Ip,
                        Desc = string.Format("{0}", desc),
                        DeviceId = par.DeviceId,
                        ClientId = par.AppClientId,
                        RunTime = watch.Elapsed.TotalMilliseconds
                    });

                    return res;
                }
                else
                {
                    //否则验证设备号认证状态
                    return VerifyDeviceStatus(par, decvice, cfg);
                }
            }

            //APP客户端ID验证
            public AuthSafeHandleCode VerifyClientId(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppClientId_ExistsCheck, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-客户端ID验证, 【LoginSafe_AppClientId_ExistsCheck】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify, "未开启APP客户端ID验证");
                }
                var code = AuthSafeHandleCode.NeedIdentityVerify;
                var desc = "";
                var watch = Stopwatch.StartNew();
                var deviceClientId = repo.DeviceRepo.FindUserDevice(par.UserId, par.AppClientId,
                    UserDeviceAuthEntity.ClientIdType);
                watch.Stop();
                if (deviceClientId == null)
                {
                    code = AuthSafeHandleCode.ContinueNextVerify;
                    desc = "用户AppClientId不存在,执行下个流程认证";
                }
                else
                {
                    if (!deviceClientId.AuthIsSuccess())
                    {
                        code =
                            cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppClientId_AuthFailAction, "100")
                                .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                        desc = code == AuthSafeHandleCode.NeedIdentityVerify
                            ? "用户AppClientId认证失败,执行身份认证"
                            : code == AuthSafeHandleCode.ContinueNextVerify
                                ? "用户AppClientId认证失败,执行下个流程验证"
                                : "用户AppClientId认证失败,允许登录";
                    }
                    else
                    {
                        code =
                            cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppClientId_AuthSuccessAction, "200")
                                .ConvertToInt32(AuthSafeHandleCode.AllowLogin);
                        desc = code == AuthSafeHandleCode.NeedIdentityVerify
                            ? "用户AppClientId认证成功,执行身份认证"
                            : code == AuthSafeHandleCode.ContinueNextVerify
                                ? "用户AppClientId认证成功,执行下个流程验证"
                                : "用户AppClientId认证成功,允许登录";
                    }
                }

                AuthSafeHandleCode res = null;
                if (AuthSafeHandleCode.NeedIdentityVerify == code)
                {
                    res = AuthSafeHandleCode.CreateCode(code
                        , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_VerifyClientIdStatus
                        , desc
                        , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                }
                else
                    res = AuthSafeHandleCode.CreateCode(code, desc);

                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "VerifyClientId",
                    ResponseCode = res.SubCode,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = desc,
                    DeviceId = par.DeviceId,
                    ClientId = par.AppClientId,
                    RunTime = watch.Elapsed.TotalMilliseconds
                });

                return res;
            }

            //设备号状态验证
            public AuthSafeHandleCode VerifyDeviceStatus(UserLoginParameter par, UserDeviceAuthEntity device,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppDevice_StatusCheck, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-设备号状态验证, 【LoginSafe_AppDevice_StatusCheck】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify, "未开启设备号验证");
                }
                var watch = Stopwatch.StartNew();
                var code = device.AuthIsSuccess()
                    ? cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppDevice_AuthSuccessAction, "200")
                        .ConvertToInt32(AuthSafeHandleCode.ContinueNextVerify)
                    : cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppDevice_AuthFailAction, "100")
                        .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                var desc = device.AuthIsSuccess()
                    ? string.Format("设备号认证成功，执行Code_{0}",code)
                    : string.Format("设备号未认证或者认证失败，执行Code_{0}", code);
                watch.Stop();

                AuthSafeHandleCode res = null;
                if (AuthSafeHandleCode.NeedIdentityVerify == code)
                {
                    res = AuthSafeHandleCode.CreateCode(code
                        , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_VerifyDeviceStatus
                        , desc
                        , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                }
                else
                {
                    res = AuthSafeHandleCode.CreateCode(code, desc);
                }

                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "VerifyDeviceStatus",
                    ResponseCode = res.SubCode,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = string.Format("{0}", desc),
                    DeviceId = par.DeviceId,
                    ClientId = par.AppClientId,
                    RunTime = watch.Elapsed.TotalMilliseconds
                });

                return res;
            }
        }

        /// <summary>
        /// 设备号黑名单验证
        /// </summary>
        public class DeviceBlacklistVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-DeviceBlacklistVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppBlacklist_Check, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-设备号黑名单, 【LoginSafe_AppBlacklist_Check】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                var key = par.DeviceId.IsEmpty() ? par.AppClientId : par.DeviceId;
                if (key.IsEmpty()) return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                var watch = Stopwatch.StartNew();
                var blackListdevice = repo.IpBlackListRepo.FindOne(YmatouBlacklistUserSpecifications.MatchDeviceId(key));
                watch.Stop();
                var code = AuthSafeHandleCode.ContinueNextVerify;
                var desc = string.Format("此设备号 {0} 不在黑名单,执行下个安全认证", par.DeviceId);
                //如果是黑名单且禁止登录时间未到期,则（根据配置）执行身份验证或者拒绝登录
                DateTime? expiredTime = null;
                if (blackListdevice != null)
                {
                    if (blackListdevice.IsDisableRequest())
                    {
                        code =
                            cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppBlacklist_BlacklistAction, "100")
                                .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                        desc = string.Format("该设备号为黑名单，执行Code_{0}", code);
                    }
                    else
                    {
                        code = AuthSafeHandleCode.ContinueNextVerify;
                        desc = "此设备号在黑名单,锁定时间已超时,执行下个安全认证";
                    }

                    expiredTime = blackListdevice.ExpiredTime.ToLocalTime();
                }

                AuthSafeHandleCode res = null;
                if (AuthSafeHandleCode.NeedIdentityVerify == code)
                {
                    res = AuthSafeHandleCode.CreateCode(code
                        , AuthSafeHandleSubCode.NeedIdentityVerify_LoginSafe_VerifyBlackDevice
                        , desc
                        , YmatouBlacklistUserSpecifications.GetLogin_NeedIdentityVerifyMessage(par.Source));
                }
                else
                {
                    res = AuthSafeHandleCode.CreateCode(code, desc);
                }

                //TODO 发布设备号黑名单事件
                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "DeviceBlacklistVerify",
                    ResponseCode = res.SubCode,
                    ExpiredTime = expiredTime ?? expiredTime.Value,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = string.Format("{0}", desc),
                    DeviceId = par.DeviceId,
                    ClientId = par.AppClientId,
                    RunTime = watch.Elapsed.TotalMilliseconds
                });

                YmatouLoggingService.Debug("登录风控-设备号黑名单验证, {0}, LoginId: {1}, key(ClientId, DeviceId): {2}, requestId: {3}", desc, par.LoginId, key, par.RequestId);

                return res;
            }
        }

        /// <summary>
        /// 用户设备号认证最后时间验证
        /// </summary>
        [Obsolete]
        public class UserAuthTokenVerify : SafeVerifyStrategyBase
        {
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                //检查IP区域token认证时间检查
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppToken_Check, "1") != "1")
                {
                    YmatouLoggingService.Debug("LoginSafe_AppToken_Check is false");
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin, "未开启token认证,允许登录");
                }
                //查找该设备最后一次认证时间
                var key = !par.DeviceId.IsEmpty() ? par.DeviceId : par.AppClientId;
                var type = !par.DeviceId.IsEmpty()
                    ? UserDeviceAuthEntity.DeviceIdType
                    : UserDeviceAuthEntity.ClientIdType;
                var watch = Stopwatch.StartNew();
                var deviceToken = repo.DeviceTokenRepo.FindLastDeviceTokenAuth(par.UserId, key, type);
                watch.Stop();
                if (deviceToken == null)
                {
                    EventBus.Instance.Publish(new LoginSafeVerifyEvent
                    {
                        UserId = par.UserId,
                        AppSource = par.Source,
                        AuthType = "VerifyDeviceTokenAuthLastTime",
                        ResponseCode = AuthSafeHandleCode.AllowLogin,
                        LoginId = par.LoginId,
                        LoginIp = par.Ip,
                        Desc = "最后一次token认证时间不存在,允许登录",
                        Summary = "-400",
                        DeviceId = par.DeviceId,
                        ClientId = par.AppClientId,
                        RunTime = watch.Elapsed.TotalMilliseconds
                    });
                    YmatouLoggingService.Debug("用户{0}最后一次token认证时间不存在,允许登录", par.LoginId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin, "最后一次token认证时间不存在,允许登录");
                }
                var subDay = DateTime.Now.Subtract(deviceToken.LastAuthTime).TotalDays;

                var lastDay = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppToken_LastAuthDay, "90").ConvertToInt32(90);
                var code = subDay >= lastDay
                    ? AuthSafeHandleCode.NeedIdentityVerify
                    : AuthSafeHandleCode.AllowLogin;
                var desc = string.Format("App最后一次token认证时间与当前时间差{0}天,{1}", Convert.ToInt32(subDay),
                    subDay >= lastDay ? "需要身份认证" : "允许登录");
                //TODO 发布最后一次token认证时间事件
                EventBus.Instance.Publish(new LoginSafeVerifyEvent
                {
                    UserId = par.UserId,
                    AppSource = par.Source,
                    AuthType = "VerifyAuthTokenLastTime",
                    ResponseCode = code,
                    LoginId = par.LoginId,
                    LoginIp = par.Ip,
                    Desc = desc,
                    DeviceId = par.DeviceId,
                    ClientId = par.AppClientId,
                    RunTime = watch.Elapsed.TotalMilliseconds
                });
                YmatouLoggingService.Debug("用户{0}，userid {1}，{2}", par.LoginId, par.UserId, desc);
                return AuthSafeHandleCode.CreateCode(code, desc);
            }
        }

        //IP黑名单验证
        public class IpBlackListVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-IpBlackListVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppIpBlacklist_Check, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-IP黑名单验证, 【LoginSafe_AppIpBlacklist_Check】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify, "未开启IP黑名单验证");
                }
                var code =
                    cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppIpBlacklist_BlacklistAction, "100")
                        .ConvertToInt32(AuthSafeHandleCode.ContinueNextVerify);
                var desc = string.Format("此IP为黑名单IP，执行Code_{0}", code);
                var result = CommonStrategy.IpBlackListVerify(par, repo, code, desc);

                YmatouLoggingService.Debug("登录风控-IP黑名单验证, LoginId: {0}, desc: {1}, requestId: {2}", par.LoginId, desc, par.RequestId);

                return result;
            }
        }

        /// <summary>
        /// 用户登录Ip区域验证
        /// </summary>
        public class IpAreaVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-IpAreaVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo
                , AuthSafeConfiguration cfg)
            {
                //检查是否开启IP区域存在性验证
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppIp_ExistsCheck, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-IP区域检查, 【LoginSafe_AppIp_ExistsCheck】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }
                //IP存在性验证
                var code = CommonStrategy.CheckUserIpArea(par, repo, cfg);
                switch (code.Code)
                {
                    case AuthSafeHandleCode.RawIpNotFind:
                    case AuthSafeHandleCode.UserFirstLogin:
                        return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify, code.Message);
                    case AuthSafeHandleCode.NeedIdentityVerify:
                        return code;
                    default:
                        break;
                }
                //检查是否开启IP区域认证状态检查
                if (cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppIp_AuthStatusCheck, "1") != "1")
                {
                    YmatouLoggingService.Debug("登录风控-IP区域检查, 【LoginSafe_AppIp_AuthStatusCheck】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify, "未开启IP区域认证");
                }

                var ipAreaRawInfo = repo.IpAreaRepo.FindIpAreaInfo(IpAreaInfoAuthEntity.IpConvertToLong(par.Ip));
                var ipAreaInfo = repo.IpAreaRepo.FindAreaInfoAuthEntity(par.UserId, ipAreaRawInfo.Country,
                    ipAreaRawInfo.Province, ipAreaRawInfo.City);
                var failCode = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppIp_AuthFailAction, "100")
                    .ConvertToInt32(AuthSafeHandleCode.NeedIdentityVerify);
                var successCode = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppIp_AuthSuccessAction, "200")
                    .ConvertToInt32(AuthSafeHandleCode.ContinueNextVerify);
                //IP区域认证状态验证
                //但IP在黑名单则再次执行认证，
                var _code = new IpBlackListVerify().Execute(par, repo, cfg);
                if (_code.Code == AuthSafeHandleCode.NeedIdentityVerify ||
                    _code.Code == AuthSafeHandleCode.DenyLogin)
                {
                    return _code;
                }
                if (ipAreaInfo == null) 
                {
                    return AuthSafeHandleCode.CreateCode(cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_PcIp_NotExistsIdentityVerify, "100").ConvertToInt32(100), "IP区域不存在");
                }
                return CommonStrategy.VerifyIPAreaStatus(par, cfg, ipAreaInfo, successCode, failCode);
            }
        }

        public class SafeAppPartialUserVerify : SafeVerifyStrategyBase
        {
            public override string ToString()
            {
                return "*SellerApp-SafeAppPartialUserVerify*";
            }
            public override AuthSafeHandleCode Execute(UserLoginParameter par, UserLoginAuthRepository repo,
                AuthSafeConfiguration cfg)
            {
                var mode = cfg.SafeCfg.TryGet(SafeCfgKey.LoginSafe_AppPartial_Mode, "0");
                if (mode.IsEmpty() || mode == "0")
                {
                    YmatouLoggingService.Debug("登录风控-灰度认证, 【LoginSafe_AppPartial_Mode】 is false; requestId: {0}", par.RequestId);
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                }

                var val = par.UserId%mode.ConvertToInt32(1);
                if (val == 0)
                    return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.ContinueNextVerify);
                return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin);
            }
        }
    }   
}
